package mrpheu.demo.server.main;

import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;

import mrpheu.demo.server.bean.MessageItem;
import mrpheu.demo.server.classes.MessageStrategyFactory;
import mrpheu.demo.server.classes.ThreadPoolChat;
import mrpheu.demo.server.constants.ChatConstant;
import mrpheu.demo.server.constants.UsingServerFlag;
import mrpheu.demo.server.implement.MrPheuTCPServer;
import mrpheu.demo.server.implement.MrPheuUDPServer;
import mrpheu.demo.server.interfaces.IMessageStrategy;
import mrpheu.demo.server.interfaces.IZoneClient;
import mrpheu.demo.server.interfaces.IZoneObserver;

public class ServerChat implements Runnable, ChatConstant, IZoneObserver {
    private Map<Integer, IZoneClient> clientList = new ConcurrentHashMap<Integer, IZoneClient>();
    public static BlockingQueue<MessageItem> messageList = new LinkedBlockingDeque<MessageItem>();
    private ThreadPoolChat threadPool = null;
    private BlockingQueue<Runnable> waitQueue = null;

//    private ServerSocket server = null;
//    private Socket socket = null;
    
    private MrPheuTCPServer tcpServer = null;
    private MrPheuUDPServer udpServer = null;
    
    private int tcpPort = 54321; // port default
    private int udpPort = 54321; // port default

    private boolean offTCPServer = false;
    private boolean offUDPServer = false;
    private boolean offMessageQueue = false;
    private UsingServerFlag usingServerFlag = UsingServerFlag.ALL;

    public ServerChat(int tcpPort, int udpPort, UsingServerFlag serverFlag) {
        this.tcpPort = tcpPort;
        this.udpPort = udpPort;
        this.waitQueue = new LinkedBlockingQueue<>(
                TOTAL_CLIENT_QUEUE_IN_THREADPOOL);
        this.threadPool = new ThreadPoolChat(TOTAL_CLIENT_SUPPORT, TOTAL_CLIENT_SUPPORT, CLIENT_KEEP_ALLOW_TIME,
                UNIT_KEEP_ALLOW_TIME, this.waitQueue);
        this.usingServerFlag = serverFlag;
        new Thread(this).start(); // listen messageList
    }

    public void event() {
        while (!offMessageQueue) {
            try {
                MessageItem messageItem = messageList.take();
                System.out.println("Lay dc message trong queue");
                if (messageItem != null) {
                    IMessageStrategy messageStrategy = MessageStrategyFactory
                            .createMessageStrategy(this.clientList, messageItem);
                    this.notify(messageStrategy);
                    System.out.println("Taked");
                }
            } catch (InterruptedException e) {
                System.out.println("Error concurrent!");
            }
        }
    }

    public void open() {
        switch (this.usingServerFlag) {
            case TCP:
                this.tcpServer = new MrPheuTCPServer(this.tcpPort, this.clientList, this.threadPool);
                break;
            case UDP:
                this.udpServer = new MrPheuUDPServer(this.udpPort, this.clientList, this.threadPool);
                break;
            default: // ALL
                this.tcpServer = new MrPheuTCPServer(this.tcpPort, this.clientList, this.threadPool);
                this.udpServer = new MrPheuUDPServer(this.udpPort, this.clientList, this.threadPool);
                break;
        }
        return;

//        try {
//            this.server = new ServerSocket(this.port);
//            System.out.println("Server started " + this.server);
//        } catch (IOException e) {
//            // TODO Auto-generated catch block
//            e.printStackTrace();
//        }

    }

    public void begin() {
        this.open();
        this.process();
    }

    public void process() {
        if (this.tcpServer != null) {
            Thread t1 = new Thread(this.tcpServer);
            t1.setPriority(Thread.MAX_PRIORITY);
            t1.start();
        }
        if (this.udpServer != null) {
            Thread t2 = new Thread(this.udpServer);
            t2.setPriority(Thread.MAX_PRIORITY);
            t2.start();
        } 
    }
    
    public void stopServer(UsingServerFlag serverFlag) {
        switch (this.usingServerFlag) {
            case TCP:
                this.tcpServer.setOffSever(false);
            case UDP:
                this.udpServer.setOffSever(false);
                break;
            default: // ALL
                this.tcpServer.setOffSever(false);
                this.udpServer.setOffSever(false);
                break;
        }
    }

    public void close() {
        if (this.tcpServer != null) {
            this.tcpServer.close();
        }
        if (this.udpServer != null) {
            this.udpServer.close();
        }
    }

    @Override
    public void notify(IMessageStrategy messageImpl) {
        System.out.println("Notify...");
        messageImpl.process();
    }

    @Override
    public void append(int id, IZoneClient client) {
        this.clientList.put(id, client);
    }

    @Override
    public void remove(int id) {
        this.clientList.remove(id);
    }

    @Override
    public void run() {
        this.event();
    }
}
